﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NetFrameworkExtensions.Mathematics
{
  public class UnivariateStatisticAccumulator : ICloneable
  {
    private double first;
    private double last;
    private double min;
    private double max;
    private double sum;
    private double weightedSum;
    private double sumSquared;
    private double weightedSumSquared;
    private int count;
    private double weight;

    public double First { get { return first; } }
    public double Last { get { return last; } }
    public double Min { get { return min; } }
    public double Max { get { return max; } }
    public double Sum { get { return sum; } }
    public double WeightedSum { get { return weightedSum; } }
    public double SumSquared { get { return sumSquared; } }
    public double WeightedSumSquared { get { return weightedSumSquared; } }
    public int Count { get { return count; } }
    public double Weight { get { return weight; } }
    public double Average { get { return sum / count; } }
    public double WeightedAverage { get { return weightedSum / weight; } }
    public double Variance { get { return (sumSquared / count) - Average * Average; } }
    public double WeightedVariance { get { return (weightedSumSquared / weight) - WeightedAverage * WeightedAverage; } }
    public double StandardDeviation { get { return Math.Sqrt(Variance); } }
    public double WeightedStandardDeviation { get { return Math.Sqrt(WeightedVariance); } }

    public void Add(double value, double weight = 1.0)
    {
      count++;
      this.weight += weight;
      sum += value;
      sumSquared += value * value;
      weightedSum += weight * value;
      weightedSumSquared += weight * value * value;
      if (count == 1)
      {
        first = value;
        min = value;
        max = value;
      }
      else
      {
        if (min > value) min = value;
        if (max < value) max = value;
      }
      last = value;
    }

    #region ICloneable Members

    object ICloneable.Clone()
    {
      return Clone();
    }

    public UnivariateStatisticAccumulator Clone()
    {
      var clone = MemberwiseClone() as UnivariateStatisticAccumulator;
      return clone;
    }

    #endregion
  }
}
